﻿using System;
using System.Collections.Generic;
using md.imi.membranes.objects.alphabet;

namespace md.imi.membranes.objects.strings
{
    public class StringObject : List<AlphabetObject>
    {
        
        //private StringObject ms;

        #region Constructors

        public StringObject()
        {
        }

        /// <summary>
        ///     Copy constructor
        /// </summary>
        /// <param name="ms"></param>
        public StringObject(StringObject ms) : this ()
        {
            foreach (var ao in ms)
            {
                this.Add(new AlphabetObject(ao));
            }
        }

        public StringObject(AlphabetObject ao)
        {
            this.Add(new AlphabetObject(ao));
        }
        #endregion

        /// <summary>
        ///     Determine if the SO can be considered terminal (composed only
        /// from terminalsymbols).
        /// </summary>
        /// <returns></returns>
        public bool IsTerminal()
        {
            // TODO: REmove this debug shortcut
            return true;

            foreach (var ao in this)
            {
                if (ao.IsTerminal == false)
                {
                    return false;
                }
            }

            return true; // all AlphabetObjects are terminal symbols
        }


        /// <summary>
        ///     hash code is used to identify unde
        /// </summary>
        public long hashCode { get; set; }

        // Not implemented in first versions
        // public int Multiplicity { get; set; }

        public override String ToString()
        {
            var result = "";
            foreach (var ao in this)
            {
                if (result.Length > 0) result += ".";
                result += ao.ToString();
            }

            result = "<" + result + ">";
            //if (Multiplicity > 1) result += "^" + Multiplicity;

            return result;
        }

        /// <summary>
        ///     Calculated location of a given substring in the passed string
        ///  Take into account and indexes
        /// </summary>
        /// <param name="stringObject"></param>
        /// <returns></returns>
        internal int getSubstringIndex(int startIndex, StringObject stringObject)
        {
            int idx = 0;

            if (startIndex >= Count || stringObject.Count == 0)
            {
                return -1;
            }

            while (startIndex < Count && idx < stringObject.Count)
            {
                if (stringObject[idx].IsEqualTo(this[startIndex]))
                {
                    idx++;
                }

                if (idx == stringObject.Count)
                {
                    if (areIndexesEqual(stringObject[idx-1], this[startIndex]))
                        return startIndex;
                }
                
                startIndex++;

            }

            return -1;
        }

        /** 
         *      Check if indexes of two alphabet objects are equal. 
         */
        private bool areIndexesEqual(AlphabetObject ao1, AlphabetObject ao2)
        {
            if (ao1 == null && ao2 == null) return true;
            if (ao1 == null || ao2 == null) return false;

            if (ao1.Indexes == null && ao2.Indexes == null) return true;
            if (ao1.Indexes == null || ao2.Indexes == null) return false;
            if (ao1.Indexes.Count == 0 && ao2.Indexes.Count == 0) return true;
            if (ao1.Indexes.Count != ao2.Indexes.Count) return false;

            for (int i = 0; i < ao1.Indexes.Count; i ++ )
            {
                if (ao1.Indexes[i] != ao2.Indexes[i]) return false;
            }

            return true;
        }


        public bool Equals (StringObject so)
        {
            if (so == null) return false;
            if (Count != so.Count) return false;

            for (int i = 0; i < Count; i ++ )
            {
                if (!this[i].ToString().Equals(so[i].ToString(), 
                    StringComparison.InvariantCultureIgnoreCase) )
                {
                    return false;
                } 
            }
            
            return true;
        }
    }
}